﻿<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>根据角色进行菜单渲染</title>
    
</head>

<body>
   <p>路由表写在前端，后端返回用户的角色，前端进行角色对象的菜单渲染</p>
   <p> 来源：https://github.com/Mrblackant/dynamicRouter-Second.git
       文章来源：https://segmentfault.com/a/1190000018727683</p>
       <p> 思路：
       分一下步骤：
       1.前端写好路由表，以及每个路由对应的角色，也就是那个角色可以看到这个菜单/路由
       2，登录的时候，向后端求得到登录用户的角色（管理员，普通用户） 
       3，利用路由拦截，根据渠道的用户角色，跟本地的路由表进行对比，过滤出用户 对应的路由，并利用路由进行左侧菜单的渲染 </p>
       具体实现

       一，前端本地写好路由表，
       我们分成两个路由，一个是固定路由，比如首页展示，每个人都能看到的，一个需要根据用户的角色动态展示
       这里我们用到了router的meta属性，我们在这里写上菜单对应的icon，对应的那些角色可以看到此单：role
       一个完整的路由表如下  --代码位置在router/index.js
       {
        path:'',
        component:layout, //整体的布局(包含左侧菜单跟主内容区域)
        children:[{
            path:'main',
            component：main,
            meta:{
                title:'首页'，//菜单名称
                roles：['user','admin'],//当前菜单哪些角色可以看到
                icon：'el-icon-info'
            }
        }]
       }



       2,2.用户登录，请求后端角色的接口，取到用户的角色，放入localStorage,然后跳转主页
       //代码位置：src/components/reLoad.vue

  // axios.post('/temp',this.formModel).then(res=>{})      
      // 我暂时就不模拟了，直接取
      let getUserRole = this.formModel.user === 'admin' ? 'admin' : 'user'
      localStorage.setItem('userRole', getUserRole)
      this.$router.push({
        path: '/main'
      })



      3，路由拦截beforeEach，并过滤出角色对应的路由表
      经过第2步，我们已经得到了用户的角色，这时候在路由拦截的地方我们就可以取到了，

取到之后，结合第1步我们写好的路由，利用数组的filter方法，拿角色跟路由表里meta标签里的roless数据进行对比

过滤好了，拿当前路由去渲染左侧菜单，这一步其实可以用vuex去实现，我担心有的小伙伴不理解，就用一个global(全局变量)替代了

//代码位置：src/permission.js

router.beforeEach((to, from, next) => {
  // 取到用户的角色
  let GetRole = localStorage.getItem("userRole")

  // 如果登录了
  if (GetRole !== 'unload') {
    next() //next()方法后的代码也会执行
    // 1.如果路由表 没根据角色进行筛选,就筛选一次
    if (!addRouFlag) {
      addRouFlag = true
      // 2.根据用户的角色、和需要动态展示的路由，生成符合用户角色的路由
      var getRoutes = baseRoleGetRouters(permissionRouter, GetRole.split(","))
      // 3.利用global属性，让渲染菜单的组件sideMeuns.vue重新生成左侧菜单
      global.antRouter = fixedRouter.concat(getRoutes)
      // 4.将生成好的路由addRoutes
      router.addRoutes(fixedRouter.concat(getRoutes))
      // 5.push之后，会重新进入到beforeEach的钩子里,直接进入第一个if判断
      router.push({ path: to.path })
    }
  } else {
    // 用户没登录，跳转到登录页面
    if (to.path === '/') {
      next()
    } else {
      next('/')
    }
  }

})


整体流程走完了，再容易让人蒙的地方

1.根据路由进行菜单展示
代码位置：/src/components/sideMeuns.vue,
先看下elementUI菜单组件,把一些基础的参数先了解一下，
这里我把菜单渲染写成了一个组件：
用到了递归属性，保证可以生成多级菜单，
我建议不熟悉的，大家用组件先模拟着写一个包含跳转功能、icon展示的菜单，然后再看我写的组件

2.用户退出系统
代码位置：/src/components/layout.vue
退出的时候，记得清除掉存在localStorage的用户角色，
然后利用 window.location.href = "/"跳转到登录页，

为什么要用location.href，这样会把之前addRoutes的路由清除掉，确保下个用户登陆后，会重新渲染正确的菜单

--------------------------------------------------------------------------------------------------------
   上面是根据角色来渲染路由的
   下面是：后台传来当前用户对应权限的路由表，前端通过调接口拿到后处理(后端处理路由)
   https://github.com/Mrblackant/dynamicRouter
   文章来源：https://segmentfault.com/a/1190000015419713


   思路整理
   以下四步骤对应的代码都在下方会讲到，并且是对应的

1.后台同学返回一个json格式的路由表，我用easymock造了一段:动态路由表，大家可参考;
2.因为后端同学传回来的都是字符串格式的，但是前端这里需要的是一个组件对象啊，写个方法遍历一下，将字符串转换为组件对象;
3.利用vue-router的beforeEach、addRoutes、localStorage来配合上边两步实现效果;
4.左侧菜单栏根据拿到转换好的路由列表进行展示;
大体步骤：拦截路由->后台取到路由->保存路由到localStorage(用户登录进来只会从后台取一次，其余都从本地取,所以用户，只有退出在登录路由才会更新)


</body>

</html>